package com.sanben.user.service.impl;

import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.RandomUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.code.kaptcha.impl.DefaultKaptcha;
import com.sanben.common.constant.Constant;
import com.sanben.common.constant.RedisKey;
import com.sanben.common.enums.ErrorMessage;
import com.sanben.common.enums.SmsTemplate;
import com.sanben.common.exception.KaptchaException;
import com.sanben.common.exception.ServiceException;
import com.sanben.common.util.*;
import com.sanben.common.web.entity.UserVO;
import com.sanben.user.data.dto.UserDto;
import com.sanben.user.data.dto.UserEditPasswordDto;
import com.sanben.user.data.dto.UserLoginDto;
import com.sanben.user.entity.User;
import com.sanben.user.mapper.UserMapper;
import com.sanben.user.service.IUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.imageio.ImageIO;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;

/**
 * @author cyh
 * @description: 用户表 服务实现类
 * @date: 2020-08-11
 */
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {

    @Autowired
    private RedisUtil redisUtil;

    @Autowired
    private DefaultKaptcha defaultKaptcha;

    @Override
    public UserVO login(UserLoginDto dto) {
        //先校验验证码是否正确
        StringBuffer stringBuffer = new StringBuffer("captcha");
        stringBuffer.append("::").append(dto.getRandomStr());
        if (!redisUtil.hasKey(stringBuffer.toString())) {
            throw new KaptchaException("验证码不存在");
        }
        String code = (String) redisUtil.get(stringBuffer.toString());
        if (!dto.getCode().equals(code)) {
            throw new KaptchaException("验证码输入不正确");
        }
        //根据账号密码查用户信息
        LambdaQueryWrapper<User> lambdaQuery = new LambdaQueryWrapper<>();
        lambdaQuery.eq(User::getUserName, dto.getUserName());
        lambdaQuery.eq(User::getPassword, MD5Util.encrypt(dto.getPassword()));
        User user = this.getOne(lambdaQuery);
        //用户不存在
        if (user == null) {
            throw new ServiceException(ErrorMessage.SYS_USER_PWD_ERROR);
        }
        //更新登录ip
        user.setIp(IpUtil.getIpAddr(ServletUtils.getRequest()));
        this.updateById(user);
        //保存用户登录信息
        UserVO userVO = BeanCopyUtils.copy(user, UserVO.class);
        userVO.setToken(IdUtil.simpleUUID());
        redisUtil.set(RedisKey.USER_TOKEN + userVO.getId(), userVO, Constant.SEVEN_HOUR_SECONDS);
        return userVO;
    }

    @Override
    public void captcha(HttpServletResponse httpServletResponse, String randomStr) {
        ByteArrayOutputStream jpegOutputStream = new ByteArrayOutputStream();
        byte[] captchaChallengeAsJpeg = null;
        try {
            //生产验证码字符串并保存到redis中
            String createText = defaultKaptcha.createText();
            System.out.println("验证码是:" + createText);
            StringBuffer stringBuffer = new StringBuffer("captcha");
            stringBuffer.append("::").append(randomStr);
            //产生的随机四位数验证码放入缓存
            redisUtil.set(stringBuffer.toString(), createText, Constant.SEX_SECONDS);
            //使用生产的验证码字符串返回一个BufferedImage对象并转为byte写入到byte数组中
            BufferedImage challenge = defaultKaptcha.createImage(createText);
            ImageIO.write(challenge, "jpg", jpegOutputStream);
            //定义response输出类型为image/jpeg类型，使用response输出流输出图片的byte数组
            captchaChallengeAsJpeg = jpegOutputStream.toByteArray();
            httpServletResponse.setHeader("Cache-Control", "no-store");
            httpServletResponse.setHeader("Pragma", "no-cache");
            httpServletResponse.setDateHeader("Expires", 0);
            httpServletResponse.setContentType("image/jpeg");
            ServletOutputStream responseOutputStream =
                    httpServletResponse.getOutputStream();
            responseOutputStream.write(captchaChallengeAsJpeg);
            responseOutputStream.flush();
            responseOutputStream.close();
        } catch (IOException e) {
            log.error("captcha random error", e);
            return;
        }
    }

    @Override
    public UserVO mobileLogin(String mobile, String code, Integer regionId) {
        User user = getUserByMobile(mobile, code);
        UserVO userVO = new UserVO();
        //账号已注册
        if (user != null) {
            userVO = BeanCopyUtils.copy(user, UserVO.class);
            userVO.setToken(IdUtil.simpleUUID());
            redisUtil.set(RedisKey.USER_TOKEN + userVO.getId(), userVO, Constant.SEVEN_HOUR_SECONDS);
            user.setIp(IpUtil.getIpAddr(ServletUtils.getRequest()));
            this.updateById(user);
        } else {
            //未注册,创建账号
            user.setMobile(mobile);
            user.setUserName(mobile);
            user.setRegionId(regionId);
            user.setPassword(MD5Util.encrypt(Constant.DEFAULT_PASSWORD));
            this.save(user);
        }
        return userVO;
    }

    @Override
    public Boolean getMobileCode(String mobile) {
        String random = RandomUtil.randomNumbers(Constant.SEX);
        String code = SsmUtil.sendSms(mobile, String.format(SmsTemplate.SYS_ERROR.getMessage(), random));
        if (code != null) {
            redisUtil.set(RedisKey.MOBILE_CODE + mobile, random, Constant.SEX_SECONDS);
            return true;
        }
        return false;
    }

    @Override
    public void register(String mobile, String code, String password) {
        User user = getUserByMobile(mobile, code);
        if (user != null) {
            throw new ServiceException(ErrorMessage.MOBILE_BEEN_REGISTER);
        } else {
            user.setUserName(mobile);
            user.setPassword(MD5Util.encrypt(password));
            this.save(user);
        }
    }

    private User getUserByMobile(String mobile, String code) {
        String redisCode = String.valueOf(redisUtil.get(RedisKey.MOBILE_CODE + mobile));
        if (!redisCode.equals(code)) {
            throw new ServiceException(ErrorMessage.SYS_MOBILE_CODE_ERROR);
        }
        LambdaQueryWrapper<User> lambdaQuery = new LambdaQueryWrapper<>();
        lambdaQuery.eq(User::getMobile, mobile);
        User user = this.getOne(lambdaQuery);
        return user;
    }

    @Override
    public void editPassword(UserEditPasswordDto dto) {
        //只能修改自己的密码
        if (!dto.getUserId().equals(ServletUtils.getUserId())) {
            throw new ServiceException(ErrorMessage.CAN_MODIFY_OWN_PASSWORD);
        }
        //两次密码不正确
        if (!MD5Util.encrypt(dto.getPassword1()).equals(dto.getPassword2())) {
            throw new ServiceException(ErrorMessage.USER_PASSWORD_NOT_SAME2);
        }
        User user = this.getById(dto.getUserId());
        //校验老密码是否正确
        if (!MD5Util.decrypt(dto.getOldPassword(), user.getPassword())) {
            throw new ServiceException(ErrorMessage.USER_PASSWORD_ERROR);
        }
        user.setPassword(MD5Util.encrypt(dto.getPassword1()));
        this.baseMapper.updateById(user);
    }

    @Override
    public Boolean updateById(UserDto dto) {
        return this.updateById(BeanCopyUtils.copy(dto, User.class));
    }

    @Override
    public User detail(Integer id) {
        return this.getById(id);
    }

    @Override
    public void loginOut(Integer userId) {
        redisUtil.del(RedisKey.USER_TOKEN+userId);
    }

}
